import type { ServiceRequest, ServiceObject, WaitingObject } from '../types';
import { MAX_SERVICE_OBJECTS, WAIT_TIME, FAN_SPEED_PRIORITY } from '../constants';

/**
 * 调度服务
 * 负责接收空调客户端的请求，并根据优先级调度+时间片调度策略进行调度
 */
export class Scheduler {
  private serviceQueue: ServiceObject[] = []; // 服务队列
  private waitingQueue: WaitingObject[] = []; // 等待队列
  private maxServiceObjects: number;
  private waitTime: number; // 等待时长（秒）
  private timers: Map<string, ReturnType<typeof setInterval>> = new Map(); // 定时器映射
  private onRoomMovedToWaitingCallback?: (roomId: string) => void; // 房间被移到等待队列的回调
  private onRoomMovedToServingCallback?: (roomId: string) => void; // 房间开始服务的回调

  constructor(maxServiceObjects: number = MAX_SERVICE_OBJECTS, waitTime: number = WAIT_TIME) {
    this.maxServiceObjects = maxServiceObjects;
    this.waitTime = waitTime;
  }

  /**
   * 设置房间被移到等待队列的回调
   */
  onRoomMovedToWaiting(callback: (roomId: string) => void): void {
    this.onRoomMovedToWaitingCallback = callback;
  }

  /**
   * 设置房间开始服务的回调
   */
  onRoomMovedToServing(callback: (roomId: string) => void): void {
    this.onRoomMovedToServingCallback = callback;
  }

  /**
   * 处理新的服务请求
   */
  handleRequest(request: ServiceRequest): {
    granted: boolean;
    message: string;
    isWaiting: boolean;
  } {
    const { roomId, targetTemp, fanSpeed } = request;

    // 检查该房间是否已在服务队列中
    const existingService = this.serviceQueue.find(s => s.roomId === roomId);
    if (existingService) {
      // 如果风速改变，则作为新请求处理
      if (existingService.fanSpeed !== fanSpeed) {
        // 移除旧的服务对象
        this.removeFromServiceQueue(roomId);
        // 作为新请求重新处理
        return this.processNewRequest(request);
      } else {
        // 仅调温，更新目标温度
        existingService.targetTemp = targetTemp;
        return {
          granted: true,
          message: '已更新目标温度',
          isWaiting: false
        };
      }
    }

    // 检查该房间是否已在等待队列中
    const existingWaiting = this.waitingQueue.find(w => w.roomId === roomId);
    if (existingWaiting) {
      // 如果风速改变，重新评估优先级
      if (existingWaiting.fanSpeed !== fanSpeed) {
        this.removeFromWaitingQueue(roomId);
        return this.processNewRequest(request);
      } else {
        // 仅调温，更新目标温度
        existingWaiting.targetTemp = targetTemp;
        return {
          granted: false,
          message: '已更新目标温度，继续等待',
          isWaiting: true
        };
      }
    }

    // 新请求处理
    return this.processNewRequest(request);
  }

  /**
   * 处理新请求
   */
  private processNewRequest(request: ServiceRequest): {
    granted: boolean;
    message: string;
    isWaiting: boolean;
  } {
    const { roomId, targetTemp, fanSpeed, currentTemp, timestamp } = request;

    // 1. 当服务对象数小于上限时，直接分配服务对象
    if (this.serviceQueue.length < this.maxServiceObjects) {
      this.addToServiceQueue({
        id: this.generateServiceId(),
        roomId,
        fanSpeed,
        targetTemp,
        currentTemp,
        serviceStartTime: timestamp,
        serviceDuration: 0,
        powerConsumption: 0,
        cost: 0
      });
      return {
        granted: true,
        message: '已分配服务对象',
        isWaiting: false
      };
    }

    // 2. 当服务对象数达到上限时，启动调度策略
    return this.applySchedulingStrategy(request);
  }

  /**
   * 应用调度策略
   */
  private applySchedulingStrategy(request: ServiceRequest): {
    granted: boolean;
    message: string;
    isWaiting: boolean;
  } {
    const { roomId, targetTemp, fanSpeed, currentTemp, timestamp } = request;
    const requestPriority = FAN_SPEED_PRIORITY[fanSpeed];

    // 找出风速低于请求风速的服务对象
    const lowerPriorityServices = this.serviceQueue.filter(
      s => FAN_SPEED_PRIORITY[s.fanSpeed] < requestPriority
    );

    // 2.1 优先级调度策略
    if (lowerPriorityServices.length > 0) {
      const serviceToReplace = this.selectServiceToReplace(lowerPriorityServices);
      
      // 将被替换的服务对象放入等待队列
      this.moveToWaitingQueue(serviceToReplace);
      
      // 分配服务对象给新请求
      this.addToServiceQueue({
        id: this.generateServiceId(),
        roomId,
        fanSpeed,
        targetTemp,
        currentTemp,
        serviceStartTime: timestamp,
        serviceDuration: 0,
        powerConsumption: 0,
        cost: 0
      });

      return {
        granted: true,
        message: '优先级调度：已分配服务对象',
        isWaiting: false
      };
    }

    // 找出风速等于请求风速的服务对象
    const samePriorityServices = this.serviceQueue.filter(
      s => FAN_SPEED_PRIORITY[s.fanSpeed] === requestPriority
    );

    // 2.2 时间片调度策略
    if (samePriorityServices.length > 0) {
      // 加入等待队列
      const waitingObj: WaitingObject = {
        roomId,
        fanSpeed,
        targetTemp,
        currentTemp,
        waitStartTime: timestamp,
        waitDuration: 0,
        assignedWaitTime: this.waitTime
      };
      this.addToWaitingQueue(waitingObj);

      // 启动等待计时器
      this.startWaitingTimer(waitingObj);

      return {
        granted: false,
        message: `时间片调度：已加入等待队列，预计等待${this.waitTime}秒`,
        isWaiting: true
      };
    }

    // 2.3 风速低于所有服务对象
    // 加入等待队列，必须等到某个服务对象空闲后才能得到服务
    const waitingObj: WaitingObject = {
      roomId,
      fanSpeed,
      targetTemp,
      currentTemp,
      waitStartTime: timestamp,
      waitDuration: 0,
      assignedWaitTime: this.waitTime
    };
    this.addToWaitingQueue(waitingObj);

    return {
      granted: false,
      message: '优先级较低：已加入等待队列',
      isWaiting: true
    };
  }

  /**
   * 选择要替换的服务对象
   */
  private selectServiceToReplace(lowerPriorityServices: ServiceObject[]): ServiceObject {
    // 2.1.3 如果多个服务对象的风速低于请求风速，且风速不相等，则将风速最低的服务对象释放
    const minPriority = Math.min(...lowerPriorityServices.map(s => FAN_SPEED_PRIORITY[s.fanSpeed]));
    const lowestPriorityServices = lowerPriorityServices.filter(
      s => FAN_SPEED_PRIORITY[s.fanSpeed] === minPriority
    );

    // 2.1.2 如果有多个服务对象的风速相等且低于请求对象，则服务时长最大的服务对象被释放
    return lowestPriorityServices.reduce((max, current) => 
      current.serviceDuration > max.serviceDuration ? current : max
    );
  }

  /**
   * 房间达到目标温度或关机，释放服务对象
   */
  releaseService(roomId: string): void {
    this.removeFromServiceQueue(roomId);
    this.processWaitingQueue();
  }

  /**
   * 处理等待队列
   * 当有服务对象空闲时，从等待队列中选择合适的请求分配服务
   */
  private processWaitingQueue(): void {
    if (this.waitingQueue.length === 0 || this.serviceQueue.length >= this.maxServiceObjects) {
      return;
    }

    // 按优先级和等待时长排序
    const sortedWaiting = [...this.waitingQueue].sort((a, b) => {
      const priorityDiff = FAN_SPEED_PRIORITY[b.fanSpeed] - FAN_SPEED_PRIORITY[a.fanSpeed];
      if (priorityDiff !== 0) return priorityDiff;
      
      // 优先级相同时，比较是否已等待满s秒
      const aComplete = a.waitDuration >= a.assignedWaitTime;
      const bComplete = b.waitDuration >= b.assignedWaitTime;
      
      if (aComplete && !bComplete) return -1;
      if (!aComplete && bComplete) return 1;
      
      // 都满s秒或都不满s秒时，按等待时长排序
      return b.waitDuration - a.waitDuration;
    });

    const nextWaiting = sortedWaiting[0];
    if (nextWaiting) {
      // 清除等待计时器
      this.clearWaitingTimer(nextWaiting.roomId);
      
      // 移除等待对象
      this.removeFromWaitingQueue(nextWaiting.roomId);
      
      // 分配服务对象
      this.addToServiceQueue({
        id: this.generateServiceId(),
        roomId: nextWaiting.roomId,
        fanSpeed: nextWaiting.fanSpeed,
        targetTemp: nextWaiting.targetTemp,
        currentTemp: nextWaiting.currentTemp,
        serviceStartTime: Date.now(),
        serviceDuration: 0,
        powerConsumption: 0,
        cost: 0
      });
      
      // 触发回调，通知房间开始服务
      if (this.onRoomMovedToServingCallback) {
        this.onRoomMovedToServingCallback(nextWaiting.roomId);
      }
    }
  }

  /**
   * 启动等待计时器
   */
  private startWaitingTimer(waitingObj: WaitingObject): void {
    const timer = setInterval(() => {
      const waiting = this.waitingQueue.find(w => w.roomId === waitingObj.roomId);
      if (!waiting) {
        this.clearWaitingTimer(waitingObj.roomId);
        return;
      }

      waiting.waitDuration += 1;

      // 如果等待时长达到分配的等待时长
      if (waiting.waitDuration >= waiting.assignedWaitTime) {
        // 检查是否可以进行时间片调度
        this.checkTimeSliceScheduling(waiting);
      }
    }, 1000);

    this.timers.set(waitingObj.roomId, timer);
  }

  /**
   * 检查时间片调度
   */
  private checkTimeSliceScheduling(waiting: WaitingObject): void {
    // 找出相同风速的服务对象
    const samePriorityServices = this.serviceQueue.filter(
      s => s.fanSpeed === waiting.fanSpeed
    );

    if (samePriorityServices.length > 0) {
      // 找出服务时长最大的服务对象
      const longestService = samePriorityServices.reduce((max, current) => 
        current.serviceDuration > max.serviceDuration ? current : max
      );

      // 替换服务对象
      this.moveToWaitingQueue(longestService);
      
      // 清除等待计时器
      this.clearWaitingTimer(waiting.roomId);
      
      // 分配服务对象给等待中的请求
      this.removeFromWaitingQueue(waiting.roomId);
      this.addToServiceQueue({
        id: this.generateServiceId(),
        roomId: waiting.roomId,
        fanSpeed: waiting.fanSpeed,
        targetTemp: waiting.targetTemp,
        currentTemp: waiting.currentTemp,
        serviceStartTime: Date.now(),
        serviceDuration: 0,
        powerConsumption: 0,
        cost: 0
      });
      
      // 触发回调，通知房间开始服务
      if (this.onRoomMovedToServingCallback) {
        this.onRoomMovedToServingCallback(waiting.roomId);
      }
    }
  }

  /**
   * 清除等待计时器
   */
  private clearWaitingTimer(roomId: string): void {
    const timer = this.timers.get(roomId);
    if (timer) {
      clearInterval(timer);
      this.timers.delete(roomId);
    }
  }

  /**
   * 更新服务对象的服务时长和当前温度
   */
  updateServiceDuration(roomId: string, duration: number, powerConsumption: number, cost: number, currentTemp: number): void {
    const service = this.serviceQueue.find(s => s.roomId === roomId);
    if (service) {
      service.serviceDuration = duration;
      service.powerConsumption = powerConsumption;
      service.cost = cost;
      service.currentTemp = currentTemp;
    }
  }

  /**
   * 更新等待队列中的当前温度
   */
  updateWaitingTemp(roomId: string, currentTemp: number): void {
    const waiting = this.waitingQueue.find(w => w.roomId === roomId);
    if (waiting) {
      waiting.currentTemp = currentTemp;
    }
  }

  /**
   * 将服务对象移至等待队列
   * 返回被移动的房间ID，以便通知ACService更新状态
   */
  private moveToWaitingQueue(service: ServiceObject): string {
    this.removeFromServiceQueue(service.roomId);
    
    const waitingObj: WaitingObject = {
      roomId: service.roomId,
      fanSpeed: service.fanSpeed,
      targetTemp: service.targetTemp,
      currentTemp: service.currentTemp,
      waitStartTime: Date.now(),
      waitDuration: 0,
      assignedWaitTime: this.waitTime
    };
    
    this.addToWaitingQueue(waitingObj);
    this.startWaitingTimer(waitingObj);
    
    // 触发回调，通知房间被移到等待队列
    if (this.onRoomMovedToWaitingCallback) {
      this.onRoomMovedToWaitingCallback(service.roomId);
    }
    
    return service.roomId;
  }

  /**
   * 添加到服务队列
   */
  private addToServiceQueue(service: ServiceObject): void {
    this.serviceQueue.push(service);
  }

  /**
   * 从服务队列移除
   */
  private removeFromServiceQueue(roomId: string): void {
    this.serviceQueue = this.serviceQueue.filter(s => s.roomId !== roomId);
  }

  /**
   * 添加到等待队列
   */
  private addToWaitingQueue(waiting: WaitingObject): void {
    this.waitingQueue.push(waiting);
  }

  /**
   * 从等待队列移除
   */
  private removeFromWaitingQueue(roomId: string): void {
    this.clearWaitingTimer(roomId);
    this.waitingQueue = this.waitingQueue.filter(w => w.roomId !== roomId);
  }

  /**
   * 生成服务对象ID
   */
  private generateServiceId(): string {
    return `service_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
  }

  /**
   * 获取服务队列
   */
  getServiceQueue(): ServiceObject[] {
    return [...this.serviceQueue];
  }

  /**
   * 获取等待队列
   */
  getWaitingQueue(): WaitingObject[] {
    return [...this.waitingQueue];
  }

  /**
   * 检查房间是否正在服务中
   */
  isServing(roomId: string): boolean {
    return this.serviceQueue.some(s => s.roomId === roomId);
  }

  /**
   * 检查房间是否在等待队列中
   */
  isWaiting(roomId: string): boolean {
    return this.waitingQueue.some(w => w.roomId === roomId);
  }

  /**
   * 清空等待队列
   */
  clearAllWaiting(): string[] {
    const roomIds = this.waitingQueue.map(w => w.roomId);
    
    // 清除所有等待计时器
    roomIds.forEach(roomId => {
      this.clearWaitingTimer(roomId);
    });
    
    // 清空等待队列
    this.waitingQueue = [];
    
    return roomIds; // 返回被清空的房间ID列表
  }

  /**
   * 清理所有定时器
   */
  destroy(): void {
    this.timers.forEach(timer => clearInterval(timer));
    this.timers.clear();
  }
}

